﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using IPC.Communication.Framework;
using IPC.Communication.Framework.Core;
using IPC.Communication.Framework.Core.IMessage;
using IPC.Communication.Framework.Core.Net;
using IPC.Communication.Framework.Reflection;

namespace IPC.Communication.Framework.Profinet.AllenBradley
{
    public class AllenBradleySLCNet : NetworkDeviceBase
    {
        public uint SessionHandle
        {
            get;
            protected set;
        }

        public AllenBradleySLCNet()
        {
            base.WordLength = 2;
            base.ByteTransform = new RegularByteTransform();
        }

        public AllenBradleySLCNet(string ipAddress, int port = 44818)
        {
            base.WordLength = 2;
            IpAddress = ipAddress;
            Port = port;
            base.ByteTransform = new RegularByteTransform();
        }

        protected override INetMessage GetNewNetMessage()
        {
            return new AllenBradleySLCMessage();
        }

        protected override OperateResult InitializationOnConnect(Socket socket)
        {
            OperateResult<byte[]> operateResult = ReadFromCoreServer(socket, "01 01 00 00 00 00 00 00 00 00 00 00 00 04 00 05 00 00 00 00 00 00 00 00 00 00 00 00".ToHexBytes());
            if (!operateResult.IsSuccess)
            {
                return operateResult;
            }
            SessionHandle = base.ByteTransform.TransUInt32(operateResult.Content, 4);
            return OperateResult.CreateSuccessResult();
        }

        //[AsyncStateMachine(typeof(<InitializationOnConnectAsync>d__8))]
        //[DebuggerStepThrough]
        //protected override Task<OperateResult> InitializationOnConnectAsync(Socket socket)
        //{
        //    <InitializationOnConnectAsync>d__8 stateMachine = new <InitializationOnConnectAsync>d__8();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.socket = socket;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        [HslMqttApi("ReadByteArray", "")]
        public override OperateResult<byte[]> Read(string address, ushort length)
        {
            OperateResult<byte[]> operateResult = BuildReadCommand(address, length);
            if (!operateResult.IsSuccess)
            {
                return operateResult;
            }
            OperateResult<byte[]> operateResult2 = ReadFromCoreServer(PackCommand(operateResult.Content));
            if (!operateResult2.IsSuccess)
            {
                return operateResult2;
            }
            OperateResult<byte[]> operateResult3 = ExtraActualContent(operateResult2.Content);
            if (!operateResult3.IsSuccess)
            {
                return operateResult3;
            }
            return OperateResult.CreateSuccessResult(operateResult3.Content);
        }

        [HslMqttApi("WriteByteArray", "")]
        public override OperateResult Write(string address, byte[] value)
        {
            OperateResult<byte[]> operateResult = BuildWriteCommand(address, value);
            if (!operateResult.IsSuccess)
            {
                return operateResult;
            }
            OperateResult<byte[]> operateResult2 = ReadFromCoreServer(PackCommand(operateResult.Content));
            if (!operateResult2.IsSuccess)
            {
                return operateResult2;
            }
            OperateResult<byte[]> operateResult3 = ExtraActualContent(operateResult2.Content);
            if (!operateResult3.IsSuccess)
            {
                return operateResult3;
            }
            return OperateResult.CreateSuccessResult(operateResult3.Content);
        }

        [HslMqttApi("ReadBool", "")]
        public override OperateResult<bool> ReadBool(string address)
        {
            int bitIndex = 0;
            address = AnalysisBitIndex(address, out bitIndex);
            OperateResult<byte[]> operateResult = Read(address, 1);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<bool>(operateResult);
            }
            return OperateResult.CreateSuccessResult(operateResult.Content.ToBoolArray()[bitIndex]);
        }

        [HslMqttApi("WriteBool", "")]
        public override OperateResult Write(string address, bool value)
        {
            OperateResult<byte[]> operateResult = BuildWriteCommand(address, value);
            if (!operateResult.IsSuccess)
            {
                return operateResult;
            }
            OperateResult<byte[]> operateResult2 = ReadFromCoreServer(PackCommand(operateResult.Content));
            if (!operateResult2.IsSuccess)
            {
                return operateResult2;
            }
            OperateResult<byte[]> operateResult3 = ExtraActualContent(operateResult2.Content);
            if (!operateResult3.IsSuccess)
            {
                return operateResult3;
            }
            return OperateResult.CreateSuccessResult(operateResult3.Content);
        }

        //[AsyncStateMachine(typeof(<ReadAsync>d__13))]
        //[DebuggerStepThrough]
        //public override Task<OperateResult<byte[]>> ReadAsync(string address, ushort length)
        //{
        //    <ReadAsync>d__13 stateMachine = new <ReadAsync>d__13();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<byte[]>>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.length = length;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<WriteAsync>d__14))]
        //[DebuggerStepThrough]
        //public override Task<OperateResult> WriteAsync(string address, byte[] value)
        //{
        //    <WriteAsync>d__14 stateMachine = new <WriteAsync>d__14();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.value = value;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<ReadBoolAsync>d__15))]
        //[DebuggerStepThrough]
        //public override Task<OperateResult<bool>> ReadBoolAsync(string address)
        //{
        //    <ReadBoolAsync>d__15 stateMachine = new <ReadBoolAsync>d__15();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<bool>>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<WriteAsync>d__16))]
        //[DebuggerStepThrough]
        //public override Task<OperateResult> WriteAsync(string address, bool value)
        //{
        //    <WriteAsync>d__16 stateMachine = new <WriteAsync>d__16();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.value = value;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        private byte[] PackCommand(byte[] coreCmd)
        {
            byte[] array = new byte[28 + coreCmd.Length];
            array[0] = 1;
            array[1] = 7;
            array[2] = (byte)(coreCmd.Length / 256);
            array[3] = (byte)(coreCmd.Length % 256);
            BitConverter.GetBytes(SessionHandle).CopyTo(array, 4);
            coreCmd.CopyTo(array, 28);
            return array;
        }

        public static string AnalysisBitIndex(string address, out int bitIndex)
        {
            bitIndex = 0;
            int num = address.IndexOf('/');
            if (num < 0)
            {
                num = address.IndexOf('.');
            }
            if (num > 0)
            {
                bitIndex = int.Parse(address.Substring(num + 1));
                address = address.Substring(0, num);
            }
            return address;
        }

        public static OperateResult<byte, byte, ushort> AnalysisAddress(string address)
        {
            if (!address.Contains(":"))
            {
                return new OperateResult<byte, byte, ushort>("Address can't find ':', example : A9:0");
            }
            string[] array = address.Split(':');
            try
            {
                OperateResult<byte, byte, ushort> operateResult = new OperateResult<byte, byte, ushort>();
                switch (array[0][0])
                {
                    case 'A':
                        operateResult.Content1 = 142;
                        break;
                    case 'B':
                        operateResult.Content1 = 133;
                        break;
                    case 'N':
                        operateResult.Content1 = 137;
                        break;
                    case 'F':
                        operateResult.Content1 = 138;
                        break;
                    case 'S':
                        operateResult.Content1 = 132;
                        break;
                    case 'C':
                        operateResult.Content1 = 135;
                        break;
                    case 'I':
                        operateResult.Content1 = 131;
                        break;
                    case 'O':
                        operateResult.Content1 = 130;
                        break;
                    case 'R':
                        operateResult.Content1 = 136;
                        break;
                    case 'T':
                        operateResult.Content1 = 134;
                        break;
                    default:
                        throw new Exception("Address code wrong, must be A,B,N,F,S,C,I,O,R,T");
                }
                if (operateResult.Content1 == 132)
                {
                    operateResult.Content2 = 2;
                }
                else
                {
                    operateResult.Content2 = byte.Parse(array[0].Substring(1));
                }
                operateResult.Content3 = ushort.Parse(array[1]);
                operateResult.IsSuccess = true;
                operateResult.Message = StringResources.Language.SuccessText;
                return operateResult;
            }
            catch (Exception ex)
            {
                return new OperateResult<byte, byte, ushort>("Wrong Address formate: " + ex.Message);
            }
        }

        public static OperateResult<byte[]> BuildReadCommand(string address, ushort length)
        {
            OperateResult<byte, byte, ushort> operateResult = AnalysisAddress(address);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult);
            }
            if (length < 2)
            {
                length = 2;
            }
            if (operateResult.Content1 == 142)
            {
                operateResult.Content3 /= 2;
            }
            byte[] array = new byte[14]
		{
			0,
			5,
			0,
			0,
			15,
			0,
			0,
			1,
			162,
			(byte)length,
			operateResult.Content2,
			operateResult.Content1,
			0,
			0
		};
            BitConverter.GetBytes(operateResult.Content3).CopyTo(array, 12);
            return OperateResult.CreateSuccessResult(array);
        }

        public static OperateResult<byte[]> BuildWriteCommand(string address, byte[] value)
        {
            OperateResult<byte, byte, ushort> operateResult = AnalysisAddress(address);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult);
            }
            if (operateResult.Content1 == 142)
            {
                operateResult.Content3 /= 2;
            }
            byte[] array = new byte[18 + value.Length];
            array[0] = 0;
            array[1] = 5;
            array[2] = 0;
            array[3] = 0;
            array[4] = 15;
            array[5] = 0;
            array[6] = 0;
            array[7] = 1;
            array[8] = 171;
            array[9] = byte.MaxValue;
            array[10] = BitConverter.GetBytes(value.Length)[0];
            array[11] = BitConverter.GetBytes(value.Length)[1];
            array[12] = operateResult.Content2;
            array[13] = operateResult.Content1;
            BitConverter.GetBytes(operateResult.Content3).CopyTo(array, 14);
            array[16] = byte.MaxValue;
            array[17] = byte.MaxValue;
            value.CopyTo(array, 18);
            return OperateResult.CreateSuccessResult(array);
        }

        public static OperateResult<byte[]> BuildWriteCommand(string address, bool value)
        {
            int bitIndex = 0;
            address = AnalysisBitIndex(address, out bitIndex);
            OperateResult<byte, byte, ushort> operateResult = AnalysisAddress(address);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult);
            }
            if (operateResult.Content1 == 142)
            {
                operateResult.Content3 /= 2;
            }
            int value2 = 1 << bitIndex;
            byte[] array = new byte[20]
		{
			0,
			5,
			0,
			0,
			15,
			0,
			0,
			1,
			171,
			255,
			2,
			0,
			operateResult.Content2,
			operateResult.Content1,
			0,
			0,
			0,
			0,
			0,
			0
		};
            BitConverter.GetBytes(operateResult.Content3).CopyTo(array, 14);
            array[16] = BitConverter.GetBytes(value2)[0];
            array[17] = BitConverter.GetBytes(value2)[1];
            if (value)
            {
                array[18] = BitConverter.GetBytes(value2)[0];
                array[19] = BitConverter.GetBytes(value2)[1];
            }
            return OperateResult.CreateSuccessResult(array);
        }

        public static OperateResult<byte[]> ExtraActualContent(byte[] content)
        {
            if (content.Length < 36)
            {
                return new OperateResult<byte[]>(StringResources.Language.ReceiveDataLengthTooShort + content.ToHexString(' '));
            }
            return OperateResult.CreateSuccessResult(content.RemoveBegin(36));
        }
    }
}
